﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.IO.Ports;

namespace QuadRemote.Tabs
{
    class BluetoothStatus : Panel
    {
        ComboBox portSelect;
        Label portStatus;
        Label portSpeed;

        int barWidth = 6;
        Timer statusTimer;

        Button connectButton;

        int graphOffsetY;
        int graphHeight;


        private long lastBytesSent = 0;
        private long lastBytesReceived = 0;
        private long lastBytesResent = 0;

        private long[] bytesSent;
        private long[] bytesReceived;
        private long[] bytesResent;

        private int graphIndex = 0;
        private int counter = 0;
        
        public BluetoothStatus()
        {
            int width = Size.Width;
            int height = Size.Height;
            //this.Size = new Size(width, height);
            this.Text = "Bluetooth connection";
            this.DoubleBuffered = true;

            int offsetY = 40;

            portSelect = new ComboBox();
            portSelect.Size = new Size(80,20);
            portSelect.Location = new Point(10, offsetY);
            portSelect.Font = Tools.getPrimaryFont();
            portSelect.DropDownStyle = ComboBoxStyle.DropDownList;
            string[] ports = SerialPort.GetPortNames();
            foreach (string p in ports)
            {
                portSelect.Items.Add(p);
                if (Properties.Settings.Default.BTPort == p)
                {
                    portSelect.SelectedIndex = portSelect.Items.Count - 1;
                }
            }
            Controls.Add(portSelect);
            portSelect.SelectedIndexChanged += new System.EventHandler(this.PortSelectChanged);

            connectButton = new Button();
            connectButton.Text = "Connect";
            connectButton.Location = new Point(100, offsetY);
            connectButton.Size = new Size(120, 30);
            connectButton.Click += connectButton_Click;
            Controls.Add(connectButton);

            portStatus = new Label();
            portStatus.Size = new Size(200, 20);
            portStatus.Location = new Point(230, offsetY);
            portStatus.Font = Tools.getPrimaryFont();
            portStatus.Text = "Disconnected";
            portStatus.ForeColor = Color.Black;
            Controls.Add(portStatus);

            offsetY += 40;

            graphOffsetY = offsetY;
            graphHeight = Height - 40 - graphOffsetY;

            offsetY += graphHeight + 5;
            portSpeed = new Label();
            portSpeed.Size = new Size(width - 20, 20);
            portSpeed.Location = new Point(10, offsetY);
            portSpeed.Font = Tools.getPrimaryFont();
            portSpeed.Text = "0 bps / 0 bps";
            portSpeed.ForeColor = Color.Black;
            Controls.Add(portSpeed);

            changeArrays();

            statusTimer = new Timer();
            statusTimer.Enabled = true;
            statusTimer.Interval = 100;
            statusTimer.Tick += new EventHandler(this.btStatus);

            this.Paint += new System.Windows.Forms.PaintEventHandler(Draw);
            Resize += BluetoothStatus_Resize;
        }

        void connectButton_Click(object sender, EventArgs e)
        {
            if (Core.Bluetooth.instance().Connect)
            {
                Core.Bluetooth.instance().Connect = false;
                portSelect.Enabled = true;
                connectButton.Text = "Connect";
            }
            else
            {
                Core.Bluetooth.instance().Connect = true;
                portSelect.Enabled = false;
                connectButton.Text = "Disconnect";
            }
        }

        void BluetoothStatus_Resize(object sender, EventArgs e)
        {
            changeArrays();
        }

        private void changeArrays()
        {
            if (this.Size.Width <= 0) return;

            bytesSent = new long[(this.Size.Width - 20) / barWidth];
            bytesReceived = new long[(this.Size.Width- 20) / barWidth];
            bytesResent = new long[(this.Size.Width - 20) / barWidth];
            graphIndex = 0;
        }
            
        public void btStatus(object Sender, EventArgs args)
        {
            int state = Core.Bluetooth.instance().state;

            if (state == Core.Bluetooth.STATE_CONNECTED) portStatus.Text = "Connected (...)";
            else if (state == Core.Bluetooth.STATE_CONNECTED_STABLE) portStatus.Text = "Connected";
            else if (state == Core.Bluetooth.STATE_CONNECTING) portStatus.Text = "Connecting...";
            else if (state == Core.Bluetooth.STATE_CONNECTING_FAILED) portStatus.Text = "Connecting failed";
            else if (state == Core.Bluetooth.STATE_CONTROL_TIMEOUT) portStatus.Text = "Connection dropped";
            else if (state == Core.Bluetooth.STATE_DISCONNECTED) portStatus.Text = "Disconnected";

            //if (counter++ < 10) return;
            counter = 0;
            long t = Core.Bluetooth.instance().bytesSent;
            bytesSent[graphIndex] = t - lastBytesSent;
            lastBytesSent = t;

            t = Core.Bluetooth.instance().bytesReceived;
            bytesReceived[graphIndex] = t - lastBytesReceived;
            lastBytesReceived = t;

            t = Core.Bluetooth.instance().bytesResent;
            bytesResent[graphIndex] = t - lastBytesResent;
            lastBytesResent = t;

            float s = 0;
            float r = 0;
            float rr = 0;

            int j = graphIndex;
            for (int i = 0; i < 1000; i += statusTimer.Interval)
            {
                s += bytesSent[j];
                r += bytesReceived[j];
                rr += bytesResent[j];
                j--;
                if (j < 0) j = bytesSent.Length - 1;
            }

            graphIndex++;
            if (graphIndex >= bytesSent.Length)
            {
                graphIndex = 0;
            }

            string sm = "TX: ";
            if (s < 512) sm += Math.Round(s) + "B/s";
            else sm += Math.Round(s / 102.4f) / 10 + "KB/s";

            sm += "    RX: ";
            if (r < 512) sm += Math.Round(r) + "B/s";
            else sm += Math.Round(r / 102.4f) / 10 + "KB/s";

            sm += "    Resent: ";
            if (rr < 512) sm += Math.Round(rr) + "B/s";
            else sm += Math.Round(rr / 102.4f) / 10 + "KB/s";

            portSpeed.Text = sm;

            this.Invalidate();
        }

        public void PortSelectChanged(object sender, EventArgs args)
        {
            if (((string)portSelect.SelectedItem.ToString()) != Properties.Settings.Default.BTPort)
            {
                Properties.Settings.Default.BTPort = (String)portSelect.SelectedItem.ToString();
                Properties.Settings.Default.Save();
            }
        }

        public virtual void Draw(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            float gH = graphHeight;
            float gOy = graphOffsetY;
            float gOx = 10;
            g.DrawRectangle(Pens.DarkGray, gOx-1, gOy-1, this.Size.Width - 20+1, gH+2);

            float maxSent = 64;
            float maxRec = 64;

            int x;
            for (x=0; x< bytesSent.Length;x++)
            {
                if (bytesSent[x] > maxSent) maxSent = bytesSent[x];
                if (bytesReceived[x] > maxRec) maxRec = bytesReceived[x];
            }

            for (x = 0; x < bytesSent.Length; x++)
            {
                float s = gH * (bytesSent[x] / maxSent);
                float r = gH * (bytesReceived[x] / maxRec);
                if (s > 0 && s < 2) s = 2;
                if (r > 0 && r < 2) r = 2;
                if (s > r)
                    g.FillRectangle(Brushes.OrangeRed, x * barWidth + gOx, gOy + gH - s, barWidth, s);

                g.FillRectangle(Brushes.Lime, x * barWidth + gOx, gOy + gH - r, barWidth, r);
                if (s <= r)
                    g.FillRectangle(Brushes.OrangeRed, x * barWidth + gOx, gOy + gH - s, barWidth, s);
            }
            
            g.DrawLine(Pens.Gray, gOx + graphIndex * barWidth, gOy, gOx + graphIndex * barWidth, gOy + gH);
        }
    }
}
